package com.xuanyue.db.xuan.antlr.v2.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//import com.xuanyue.db.xuan.SeachContext;
import com.xuanyue.db.xuan.SeachContextV2;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.AndConditionContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.ConditionElementContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.ConditionExprContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.DeleteContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.GroupConditionContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.OrConditionContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.QueryContext;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser.UpdateContext;
import com.xuanyue.db.xuan.core.db.ColumnMetaV2;
import com.xuanyue.db.xuan.core.db.TableMetaV2;
import com.xuanyue.db.xuan.core.exception.SQLException;
import com.xuanyue.db.xuan.core.table.IColumn;
import com.xuanyue.db.xuan.core.table.expr.Expr;
import com.xuanyue.db.xuan.core.table.expr.ExprValue;
import com.xuanyue.db.xuan.core.table.expr.ExprValueType;
import com.xuanyue.db.xuan.core.table.expr.Function;
import com.xuanyue.db.xuan.core.table.expr.IFunctionExecutor;
import com.xuanyue.db.xuan.core.table.expr.LimitInfo;
import com.xuanyue.db.xuan.core.table.expr.Settor;
import com.xuanyue.db.xuan.core.table.expr.SortTemplate;
/**
 * 1、计算所需最大内存资源
 * 2、检查sql 是否有错误
 *
 * @author 解观海
 * @email guanhaixie@sina.cn
 * @date 2020年11月24日
 *
 */
public class ProofreaderListenerImplV2 extends AbstractBitQV2Listener{
	private static Logger logger = LoggerFactory.getLogger(ProofreaderListenerImplV2.class);
	
	private int source;
	private int now=-1;
	
	public int getMaxSource() {
		return source;
	}
	
	@Override
	protected void handle(boolean notIsNull) {
		if(logger.isDebugEnabled())
			logger.debug(String.format("expr 'not' operator ,caches index:%s", now));
	}

	@Override
	protected int handle(Expr expr) {
		
		ExprValue ev = expr.getValue();
		if(ExprValueType.TRANSATTR.is(ev.getType())) {//替换传参方式的值
			Map<String,ExprValue> ps = this.getSingleParameter().getValue();
			String key = ev.getValue();
			expr.setValue( ps.get(key) );
		}
		
		int source = table.checkAndContSource(expr);
		expr.setValue(ev);//保持参数的不变性
		pp(source);
		reduce(source);
		return source;
	}

	@Override
	protected int handle(Function function) {
		IFunctionExecutor<? extends IColumn> iFunction = SeachContextV2.getFunction(function.getFunctionName());
		ExprValue ev;
		List<ExprValue> evl = function.getValues();
		List<ExprValue> evs = new ArrayList<>();
		for(int i=0,s=evl.size();i<s;i++	) {
			ev = evl.get(i);
			if(ExprValueType.TRANSATTR.is(ev.getType())) {//替换传参方式的值
				Map<String,ExprValue> ps = this.getSingleParameter().getValue();
				String key = ev.getValue();
				evs.add( new ExprValue(ps.get(key).getType(),ps.get(key).getValue())  );
			}else {
				evs.add( ev );
			}
		}
		int source = iFunction.exprCheck(table.getColumn(function.getCname()), new ExprValue(ExprValueType.ARRAY,  evs));
		//iFunction.exprExe(table.getColumn(function.getCname()), new ExprValue(ExprValueType.ARRAY,function.getValues()), caches.subList(now, caches.size()));
		pp(source);
		reduce(source);
		return source;
	}

	@Override
	protected void handle(List<SortTemplate> sortTemplateList, LimitInfo limitInfo) {
		if(sortTemplateList==null) {
			pp();
			reduce();
		}else {
			pp(5);
			reduce(5);
		}
	}

	private boolean checkSettors(List<Settor> settors,ExprValue vs) {
		Map<String,ExprValue> ps = (vs==null?null:vs.getValue());
		ExprValue v;
		String key = null;
		for(Settor settor:settors) {
			v=settor.getExprValue();
			if(ExprValueType.TRANSATTR.is(v.getType())) {
				if(vs==null) {
					return false;
				}else {
					key = v.getValue();
					v=ps.get(String.format("?%s",  key));
				}
			}
			if(!table.getColumn(settor.getCname()).checkType(v)) {
				return false;
			}
		}
		return true;
	}
	
	@Override
	protected void exeUpdate(List<Settor> settors) {
		assert settors!=null:"settors can not be null ";
		if(isBatch()) {
			throw new SQLException("not support batch execute on update");
		}
		ExprValue vs=getSingleParameter();
		if(!checkSettors(settors, vs)) {
			throw new SQLException("set value ERROR :");
		}
	}

	@Override
	protected void exeDelete() {
		if(isBatch()) {
			throw new SQLException("not support batch execute on delete");
		}
	}

	@Override
	protected void exeInsertInto(Map<String, ExprValue> c2Value) { 
		
		if(isBatch()) {
			List<ExprValue> vsL = getBatchParameter();
			Map<String, ExprValue> c2p;// = new HashMap<>();
			for(int i=0,s=vsL.size();i<s;i++) {
				c2p=vsL.get(i).getValue();
				for(Entry<String,ExprValue> en:c2Value.entrySet()) {
					if(ExprValueType.TRANSATTR.is(en.getValue().getType() )) {
						if(!c2p.containsKey(en.getKey())) {
							throw new SQLException(String.format("error :excute batch error at index %s,not exists the value of %s", i,en.getKey()));
						}
						if(!table.getColumn(en.getKey()).checkType(c2p.get(en.getKey())  )) {
							throw new SQLException(String.format("error :excute batch error at index %s, the type of the value type ( %s)", i,en.getKey()));
						}
					}else {
						if(!table.getColumn(en.getKey()).checkType( en.getValue())) {
							throw new SQLException(String.format("error :excute batch error at index %s, the type of the value type ( %s)", i,en.getKey()));
						}
					}
				}
			}
		}else if(hasParameter()){
			ExprValue vs=getSingleParameter();
			Map<String, ExprValue> c2p=vs.getValue();
			for(Entry<String,ExprValue> en:c2Value.entrySet()) {
				if(ExprValueType.TRANSATTR.is(en.getValue().getType() )) {
					if(!c2p.containsKey(en.getKey())) {
						throw new SQLException(String.format("error :not exists the value of %s",en.getKey()));
					}
					if(!table.getColumn(en.getKey()).checkType(c2p.get(en.getKey())  )) {
						throw new SQLException(String.format("error :the type of the value type ( %s)", en.getKey()));
					}
				}else {
					if(!table.getColumn(en.getKey()).checkType( en.getValue())) {
						throw new SQLException(String.format("error :the type of the value type ( %s)", en.getKey()));
					}
				}
			}
		}else {
			//无参数
			for(Entry<String,ExprValue> en:c2Value.entrySet()) {
				if(ExprValueType.TRANSATTR.is(en.getValue().getType() )) {
					throw new SQLException(String.format("error :not exists the parameter value of %s",en.getKey()));
				}else {
					if(!table.getColumn(en.getKey()).checkType( en.getValue())) {
						throw new SQLException(String.format("error :the type of the value type ( %s)", en.getKey()));
					}
				}
			}
		}
	}

	@Override
	protected void exeCreateTable(TableMetaV2 tableMetaV2) { 
		if(SeachContextV2.getTable(tableMetaV2.getName().toLowerCase())!=null) {
			throw new SQLException(String.format("the table name %s has existed ",tableMetaV2.getName() ));
		}
	}

	@Override
	protected void exeSetSource(int source) { }

	@Override
	protected void exeDropColumn(String cname) {
		if(table.getColumn(cname)==null) {
			throw new SQLException("the column "+ cname+"  is not exists");
		}
	}

	@Override
	protected void exeAddColumn(ColumnMetaV2 cmV2) {
		if(table.getColumn(cmV2.getName())!=null) {
			throw new SQLException("the column name "+ cmV2.getName()+"  has existed");
		}
		
	}
	@Override
	protected void exeAlertColumn(String oldName,ColumnMetaV2 cmV2) {
		if(table.getColumn(oldName)==null) {
			throw new SQLException("the column "+ oldName+"  is not exists");
		}
		if(!SeachContextV2.checkAlertColumn(table.getName(), oldName, cmV2)) {
			throw new SQLException(" the old column type   is different from the  new one");
		}
	}
	@Override
	protected void handle(ConditionExprContext expr) {
		pp();
		super.handle(expr);
		reduce();
	}
	
	@Override
	protected void handle(GroupConditionContext group) {
		pp();
		super.handle(group);
		reduce();
	}
	
	@Override
	protected void handle(ConditionElementContext ele) {
		pp();
		super.handle(ele);
		reduce();
	}
	
	@Override
	protected void handle(AndConditionContext andCondition) {
		pp();
		super.handle(andCondition);
		reduce();
	}
	
	@Override
	protected void handle(OrConditionContext or) {
		pp();
		super.handle(or);
		reduce();
	}
	
	@Override
	protected void handle(QueryContext query) {
		//初始化一个无限列表
		pp();
		super.handle(query);
		reduce();
	}
	
	@Override
	protected void handle(UpdateContext update) {
		pp();
		super.handle(update);
		reduce();
	}

	@Override
	protected void handle(DeleteContext delete) {
		pp();
		super.handle(delete);
		reduce();
	}

	private void pp() {
		now++;
		if(source<now) {
			source=now;
		}
	}
	private void pp(int num) {
		now+=num;
		if(source<now) {
			source=now;
		}
	}
	private void reduce() {
		now--;
	}
	private void reduce(int num) {
		now-=num;
	}

	@Override
	protected void exeOr(int offset) {}
	@Override
	protected void exeAnd(int offset) {}
	@Override
	protected void exeSetAll(boolean value) { }
	@Override
	protected void exeAndMask() { }
	@Override
	protected void exeApplySrouce() { }
	@Override
	protected void exeReturnSrouce() { }
	@Override
	protected void exePP() { }
	@Override
	protected void exeReduce() { }
	@Override
	protected void exeCopyMask() {}

	@Override
	protected void exeVersionRemember() {}

	@Override
	protected ReadLock getReadLockOfMeta() {
		return null;
	}

	@Override
	protected WriteLock getWriteLockOfMeta() {
		// TODO Auto-generated method stub
		return null;
	}
	
}
